home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / pyshared / PIL / ArgImagePlugin.py < prev    next >
Text File  |  2006-12-03  |  12KB  |  499 lines

  1. #
  2. # THIS IS WORK IN PROGRESS
  3. #
  4. # The Python Imaging Library.
  5. # $Id: ArgImagePlugin.py 2309 2005-03-02 15:06:34Z fredrik $
  6. #
  7. # ARG animation support code
  8. #
  9. # history:
  10. # 1996-12-30 fl   Created
  11. # 1996-01-06 fl   Added safe scripting environment
  12. # 1996-01-10 fl   Added JHDR, UHDR and sYNC support
  13. # 2005-03-02 fl   Removed AAPP and ARUN support
  14. #
  15. # Copyright (c) Secret Labs AB 1997.
  16. # Copyright (c) Fredrik Lundh 1996-97.
  17. #
  18. # See the README file for information on usage and redistribution.
  19. #
  20.  
  21. __version__ = "0.4"
  22.  
  23. import marshal, string
  24.  
  25. import Image, ImageFile, ImagePalette
  26.  
  27. from PngImagePlugin import i16, i32, ChunkStream, _MODES
  28.  
  29. MAGIC = "\212ARG\r\n\032\n"
  30.  
  31. # --------------------------------------------------------------------
  32. # ARG parser
  33.  
  34. class ArgStream(ChunkStream):
  35.     "Parser callbacks for ARG data"
  36.  
  37.     def __init__(self, fp):
  38.  
  39.         ChunkStream.__init__(self, fp)
  40.  
  41.         self.eof = 0
  42.  
  43.         self.im = None
  44.         self.palette = None
  45.  
  46.         self.__reset()
  47.  
  48.     def __reset(self):
  49.  
  50.         # reset decoder state (called on init and sync)
  51.  
  52.         self.count = 0
  53.         self.id = None
  54.         self.action = ("NONE",)
  55.  
  56.         self.images = {}
  57.         self.names = {}
  58.  
  59.  
  60.     def chunk_AHDR(self, offset, bytes):
  61.         "AHDR -- animation header"
  62.  
  63.         # assertions
  64.         if self.count != 0:
  65.             raise SyntaxError, "misplaced AHDR chunk"
  66.  
  67.         s = self.fp.read(bytes)
  68.         self.size = i32(s), i32(s[4:])
  69.         try:
  70.             self.mode, self.rawmode = _MODES[(ord(s[8]), ord(s[9]))]
  71.         except:
  72.             raise SyntaxError, "unknown ARG mode"
  73.  
  74.         if Image.DEBUG:
  75.             print "AHDR size", self.size
  76.             print "AHDR mode", self.mode, self.rawmode
  77.  
  78.         return s
  79.  
  80.     def chunk_AFRM(self, offset, bytes):
  81.         "AFRM -- next frame follows"
  82.  
  83.         # assertions
  84.         if self.count != 0:
  85.             raise SyntaxError, "misplaced AFRM chunk"
  86.  
  87.         self.show = 1
  88.         self.id = 0
  89.         self.count = 1
  90.         self.repair = None
  91.  
  92.         s = self.fp.read(bytes)
  93.         if len(s) >= 2:
  94.             self.id = i16(s)
  95.             if len(s) >= 4:
  96.                 self.count = i16(s[2:4])
  97.                 if len(s) >= 6:
  98.                     self.repair = i16(s[4:6])
  99.                 else:
  100.                     self.repair = None
  101.  
  102.         if Image.DEBUG:
  103.             print "AFRM", self.id, self.count
  104.  
  105.         return s
  106.  
  107.     def chunk_ADEF(self, offset, bytes):
  108.         "ADEF -- store image"
  109.  
  110.         # assertions
  111.         if self.count != 0:
  112.             raise SyntaxError, "misplaced ADEF chunk"
  113.  
  114.         self.show = 0
  115.         self.id = 0
  116.         self.count = 1
  117.         self.repair = None
  118.  
  119.         s = self.fp.read(bytes)
  120.         if len(s) >= 2:
  121.             self.id = i16(s)
  122.             if len(s) >= 4:
  123.                 self.count = i16(s[2:4])
  124.  
  125.         if Image.DEBUG:
  126.             print "ADEF", self.id, self.count
  127.  
  128.         return s
  129.  
  130.     def chunk_NAME(self, offset, bytes):
  131.         "NAME -- name the current image"
  132.  
  133.         # assertions
  134.         if self.count == 0:
  135.             raise SyntaxError, "misplaced NAME chunk"
  136.  
  137.         name = self.fp.read(bytes)
  138.         self.names[self.id] = name
  139.  
  140.         return name
  141.  
  142.     def chunk_AEND(self, offset, bytes):
  143.         "AEND -- end of animation"
  144.  
  145.         if Image.DEBUG:
  146.             print "AEND"
  147.  
  148.         self.eof = 1
  149.  
  150.         raise EOFError, "end of ARG file"
  151.  
  152.     def __getmodesize(self, s, full=1):
  153.  
  154.         size = i32(s), i32(s[4:])
  155.  
  156.         try:
  157.             mode, rawmode = _MODES[(ord(s[8]), ord(s[9]))]
  158.         except:
  159.             raise SyntaxError, "unknown image mode"
  160.  
  161.         if full:
  162.             if ord(s[12]):
  163.                 pass # interlace not yet supported
  164.             if ord(s[11]):
  165.                 raise SyntaxError, "unknown filter category"
  166.  
  167.         return size, mode, rawmode
  168.  
  169.     def chunk_PAST(self, offset, bytes):
  170.         "PAST -- paste one image into another"
  171.  
  172.         # assertions
  173.         if self.count == 0:
  174.             raise SyntaxError, "misplaced PAST chunk"
  175.  
  176.         if self.repair is not None:
  177.             # we must repair the target image before we
  178.             # start pasting
  179.  
  180.             # brute force; a better solution would be to
  181.             # update only the dirty rectangles in images[id].
  182.             # note that if images[id] doesn't exist, it must
  183.             # be created
  184.  
  185.             self.images[self.id] = self.images[self.repair].copy()
  186.             self.repair = None
  187.  
  188.         s = self.fp.read(bytes)
  189.         im = self.images[i16(s)]
  190.         x, y = i32(s[2:6]), i32(s[6:10])
  191.         bbox = x, y, im.size[0]+x, im.size[1]+y
  192.  
  193.         if im.mode in ["RGBA"]:
  194.             # paste with transparency
  195.             # FIXME: should handle P+transparency as well
  196.             self.images[self.id].paste(im, bbox, im)
  197.         else:
  198.             # paste without transparency
  199.             self.images[self.id].paste(im, bbox)
  200.  
  201.         self.action = ("PAST",)
  202.         self.__store()
  203.  
  204.         return s
  205.  
  206.     def chunk_BLNK(self, offset, bytes):
  207.         "BLNK -- create blank image"
  208.  
  209.         # assertions
  210.         if self.count == 0:
  211.             raise SyntaxError, "misplaced BLNK chunk"
  212.  
  213.         s = self.fp.read(bytes)
  214.         size, mode, rawmode = self.__getmodesize(s, 0)
  215.  
  216.         # store image (FIXME: handle colour)
  217.         self.action = ("BLNK",)
  218.         self.im = Image.core.fill(mode, size, 0)
  219.         self.__store()
  220.  
  221.         return s
  222.  
  223.     def chunk_IHDR(self, offset, bytes):
  224.         "IHDR -- full image follows"
  225.  
  226.         # assertions
  227.         if self.count == 0:
  228.             raise SyntaxError, "misplaced IHDR chunk"
  229.  
  230.         # image header
  231.         s = self.fp.read(bytes)
  232.         size, mode, rawmode = self.__getmodesize(s)
  233.  
  234.         # decode and store image
  235.         self.action = ("IHDR",)
  236.         self.im = Image.core.new(mode, size)
  237.         self.decoder = Image.core.zip_decoder(rawmode)
  238.         self.decoder.setimage(self.im, (0,0) + size)
  239.         self.data = ""
  240.  
  241.         return s
  242.  
  243.     def chunk_DHDR(self, offset, bytes):
  244.         "DHDR -- delta image follows"
  245.  
  246.         # assertions
  247.         if self.count == 0:
  248.             raise SyntaxError, "misplaced DHDR chunk"
  249.  
  250.         s = self.fp.read(bytes)
  251.  
  252.         size, mode, rawmode = self.__getmodesize(s)
  253.  
  254.         # delta header
  255.         diff = ord(s[13])
  256.         offs = i32(s[14:18]), i32(s[18:22])
  257.  
  258.         bbox = offs + (offs[0]+size[0], offs[1]+size[1])
  259.  
  260.         if Image.DEBUG:
  261.             print "DHDR", diff, bbox
  262.  
  263.         # FIXME: decode and apply image
  264.         self.action = ("DHDR", diff, bbox)
  265.  
  266.         # setup decoder
  267.         self.im = Image.core.new(mode, size)
  268.  
  269.         self.decoder = Image.core.zip_decoder(rawmode)
  270.         self.decoder.setimage(self.im, (0,0) + size)
  271.  
  272.         self.data = ""
  273.  
  274.         return s
  275.  
  276.     def chunk_JHDR(self, offset, bytes):
  277.         "JHDR -- JPEG image follows"
  278.  
  279.         # assertions
  280.         if self.count == 0:
  281.             raise SyntaxError, "misplaced JHDR chunk"
  282.  
  283.         # image header
  284.         s = self.fp.read(bytes)
  285.         size, mode, rawmode = self.__getmodesize(s, 0)
  286.  
  287.         # decode and store image
  288.         self.action = ("JHDR",)
  289.         self.im = Image.core.new(mode, size)
  290.         self.decoder = Image.core.jpeg_decoder(rawmode)
  291.         self.decoder.setimage(self.im, (0,0) + size)
  292.         self.data = ""
  293.  
  294.         return s
  295.  
  296.     def chunk_UHDR(self, offset, bytes):
  297.         "UHDR -- uncompressed image data follows (EXPERIMENTAL)"
  298.  
  299.         # assertions
  300.         if self.count == 0:
  301.             raise SyntaxError, "misplaced UHDR chunk"
  302.  
  303.         # image header
  304.         s = self.fp.read(bytes)
  305.         size, mode, rawmode = self.__getmodesize(s, 0)
  306.  
  307.         # decode and store image
  308.         self.action = ("UHDR",)
  309.         self.im = Image.core.new(mode, size)
  310.         self.decoder = Image.core.raw_decoder(rawmode)
  311.         self.decoder.setimage(self.im, (0,0) + size)
  312.         self.data = ""
  313.  
  314.         return s
  315.  
  316.     def chunk_IDAT(self, offset, bytes):
  317.         "IDAT -- image data block"
  318.  
  319.         # pass compressed chunks through the decoder
  320.         s = self.fp.read(bytes)
  321.         self.data = self.data + s
  322.         n, e = self.decoder.decode(self.data)
  323.         if n < 0:
  324.             # end of image
  325.             if e < 0:
  326.                 raise IOError, "decoder error %d" % e
  327.         else:
  328.             self.data = self.data[n:]
  329.  
  330.         return s
  331.  
  332.     def chunk_DEND(self, offset, bytes):
  333.         return self.chunk_IEND(offset, bytes)
  334.  
  335.     def chunk_JEND(self, offset, bytes):
  336.         return self.chunk_IEND(offset, bytes)
  337.  
  338.     def chunk_UEND(self, offset, bytes):
  339.         return self.chunk_IEND(offset, bytes)
  340.  
  341.     def chunk_IEND(self, offset, bytes):
  342.         "IEND -- end of image"
  343.  
  344.         # we now have a new image.  carry out the operation
  345.         # defined by the image header.
  346.  
  347.         # won't need these anymore
  348.         del self.decoder
  349.         del self.data
  350.  
  351.         self.__store()
  352.  
  353.         return self.fp.read(bytes)
  354.  
  355.     def __store(self):
  356.  
  357.         # apply operation
  358.         cid = self.action[0]
  359.  
  360.         if cid in ["BLNK", "IHDR", "JHDR", "UHDR"]:
  361.             # store
  362.             self.images[self.id] = self.im
  363.  
  364.         elif cid == "DHDR":
  365.             # paste
  366.             cid, mode, bbox = self.action
  367.             im0 = self.images[self.id]
  368.             im1 = self.im
  369.             if mode == 0:
  370.                 im1 = im1.chop_add_modulo(im0.crop(bbox))
  371.             im0.paste(im1, bbox)
  372.  
  373.         self.count = self.count - 1
  374.  
  375.         if self.count == 0 and self.show:
  376.             self.im = self.images[self.id]
  377.             raise EOFError # end of this frame
  378.  
  379.     def chunk_PLTE(self, offset, bytes):
  380.         "PLTE -- palette data"
  381.  
  382.         s = self.fp.read(bytes)
  383.         if self.mode == "P":
  384.             self.palette = ImagePalette.raw("RGB", s)
  385.         return s
  386.  
  387.     def chunk_sYNC(self, offset, bytes):
  388.         "SYNC -- reset decoder"
  389.  
  390.         if self.count != 0:
  391.             raise SyntaxError, "misplaced sYNC chunk"
  392.  
  393.         s = self.fp.read(bytes)
  394.         self.__reset()
  395.         return s
  396.  
  397.  
  398. # --------------------------------------------------------------------
  399. # ARG reader
  400.  
  401. def _accept(prefix):
  402.     return prefix[:8] == MAGIC
  403.  
  404. ##
  405. # Image plugin for the experimental Animated Raster Graphics format.
  406.  
  407. class ArgImageFile(ImageFile.ImageFile):
  408.  
  409.     format = "ARG"
  410.     format_description = "Animated raster graphics"
  411.  
  412.     def _open(self):
  413.  
  414.         if self.fp.read(8) != MAGIC:
  415.             raise SyntaxError, "not an ARG file"
  416.  
  417.         self.arg = ArgStream(self.fp)
  418.  
  419.         # read and process the first chunk (AHDR)
  420.  
  421.         cid, offset, bytes = self.arg.read()
  422.  
  423.         if cid != "AHDR":
  424.             raise SyntaxError, "expected an AHDR chunk"
  425.  
  426.         s = self.arg.call(cid, offset, bytes)
  427.  
  428.         self.arg.crc(cid, s)
  429.  
  430.         # image characteristics
  431.         self.mode = self.arg.mode
  432.         self.size = self.arg.size
  433.  
  434.     def load(self):
  435.  
  436.         if self.arg.im is None:
  437.             self.seek(0)
  438.  
  439.         # image data
  440.         self.im = self.arg.im
  441.         self.palette = self.arg.palette
  442.  
  443.         # set things up for further processing
  444.         Image.Image.load(self)
  445.  
  446.     def seek(self, frame):
  447.  
  448.         if self.arg.eof:
  449.             raise EOFError, "end of animation"
  450.  
  451.         self.fp = self.arg.fp
  452.  
  453.         while 1:
  454.  
  455.             #
  456.             # process chunks
  457.  
  458.             cid, offset, bytes = self.arg.read()
  459.  
  460.             if self.arg.eof:
  461.                 raise EOFError, "end of animation"
  462.  
  463.             try:
  464.                 s = self.arg.call(cid, offset, bytes)
  465.             except EOFError:
  466.                 break
  467.  
  468.             except "glurk": # AttributeError
  469.                 if Image.DEBUG:
  470.                     print cid, bytes, "(unknown)"
  471.                 s = self.fp.read(bytes)
  472.  
  473.             self.arg.crc(cid, s)
  474.  
  475.         self.fp.read(4) # ship extra CRC
  476.  
  477.     def tell(self):
  478.         return 0
  479.  
  480.     def verify(self):
  481.         "Verify ARG file"
  482.  
  483.         # back up to first chunk
  484.         self.fp.seek(8)
  485.  
  486.         self.arg.verify(self)
  487.         self.arg.close()
  488.  
  489.         self.fp = None
  490.  
  491. #
  492. # --------------------------------------------------------------------
  493.  
  494. Image.register_open("ARG", ArgImageFile, _accept)
  495.  
  496. Image.register_extension("ARG", ".arg")
  497.  
  498. Image.register_mime("ARG", "video/x-arg")
  499.